Skip to main content

Connection Limiting

Connection limiting restricts the number of simultaneous (concurrent) connections a client can open to your NGINX server.

It is implemented using the limit_conn module and protects against:

  • Slowloris attacks
  • Connection-flood DDoS attacks
  • Resource exhaustion (worker connections, memory)
  • Abuse from bots and crawlers
  • Misbehaving clients holding connections open

Key difference from rate limiting:

limit_conn limits how many connections are open at the same time, not how many requests are sent per second.

How limit_conn Works (Internals)​

NGINX maintains a shared memory counter:

  1. Each new connection increments a counter
  2. Counter is keyed by:
    • IP address
    • Server
    • Custom variable
  3. When the limit is exceeded:
    • Connection is rejected immediately
  4. Counter is decremented when the connection closes

This is a hard limit (no queuing, no delays).

Core Directives of limit_conn​

limit_conn_zone (Define the Connection Zone)​

limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
ComponentMeaning
$binary_remote_addrClient identifier (IP)
zone=conn_limit:10mShared memory zone
10mStores ~160,000 unique keys

Uses binary format → more memory-efficient

limit_conn (Apply the Limit)​

limit_conn conn_limit 10;
PartMeaning
conn_limitZone name
10Max concurrent connections

limit_conn_status (Custom Status Code)​

limit_conn_status 429;

Default is 503 Service Unavailable

Basic Example: Limit Connections Per IP​

http {
limit_conn_zone $binary_remote_addr zone=per_ip:10m;

server {
listen 80;

location / {
limit_conn per_ip 10;
}
}
}
  • Each IP can open 10 concurrent connections
  • 11th connection is rejected

Protecting Against Slowloris Attacks​

Slowloris holds many connections open with slow headers.

limit_conn_zone $binary_remote_addr zone=slowloris:10m;

server {
listen 443 ssl;

limit_conn slowloris 5;

client_header_timeout 10s;
client_body_timeout 10s;
}
  • Max 5 open connections per IP
  • Timeouts close slow connections

Limiting Connections Per Server (Global Cap)​

limit_conn_zone $server_name zone=per_server:10m;

server {
listen 80;
limit_conn per_server 1000;
}
  • Backend has limited capacity
  • You want a hard cap per virtual host

API / WebSocket Connection Limiting​

WebSockets keep connections open for a long time.

limit_conn_zone $binary_remote_addr zone=ws:10m;

location /ws/ {
limit_conn ws 2;
proxy_pass http://ws_backend;
}

Combining limit_conn with limit_req​

limit_req_zone  $binary_remote_addr zone=req:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=conn:10m;

server {
listen 443 ssl;

location /api/ {
limit_req zone=req burst=20 nodelay;
limit_conn conn 10;
proxy_pass http://api_backend;
}
}
ThreatProtection
HTTP floodlimit_req
Slow clientslimit_conn
Resource exhaustionBoth

Limiting Connections Behind a Load Balancer​

Fix Real Client IP

set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;

Then:

limit_conn_zone $binary_remote_addr zone=realip:10m;
limit_conn realip 20;

📌 Without this:

  • All users appear as one IP
  • Limits become useless

Common Security Mistakes​

MistakeRisk
Too high connection limitIneffective protection
Too low limitLegit users blocked
Not setting timeoutsSlowloris still possible
No real IP handlingAll users share same bucket
Only using limit_connHTTP floods still succeed

Testing Connection Limits​

Open Multiple Connections

ab -n 1000 -c 50 http://example.com/

Expected: Some requests fail with 429 or 503

Check logs

error_log /var/log/nginx/error.log notice;

limit_conn vs limit_req​

Featurelimit_connlimit_req
LimitsConcurrent connectionsRequests per second
Queueing❌ No✔ Yes
Best forSlowloris, WebSocketsAPIs, login endpoints
limit_conn_zone $binary_remote_addr zone=conn:10m;
limit_conn_status 429;

server {
limit_conn conn 10;
client_header_timeout 10s;
client_body_timeout 10s;
}